package main

import (
	"net"
	"errors"
	"fmt"
	"time"
	"sync"
	"ketama"
)

/* TO DO : i don't know why 10 , should use anther better number like CPU number*2 */

type ChannelMap struct {
	sync.Mutex
	cmap map[string]*Channel
}


var ChannelMapInstance map[string]*ChannelMap
var ring *ketama.HashRing

func InitChannelMap()  {
	InitRoomMap()
	ChannelMapInstance = make(map[string]*ChannelMap)
	ring = ketama.NewRing(255)
	for i:= 0;i < 10 ;i++ {
		ChannelMapInstance[string(i)] = NewChannelMap()
		ring.AddNode(string(i),1)
	}
	ring.Bake()
	go montorChannelMap()
}

func NewChannelMap() *ChannelMap{
	c := new(ChannelMap)
	c.cmap = make(map[string]*Channel)
	return c
}


func AddChannel(userid string,conn *net.TCPConn) (*Channel,string){
	token := UserRouterI.PutToRouter(userid)
	c := NewChannel(token,conn)
	go c.HandleMsg()

	cmap := GetChannelMap(token)
	cmap.Lock()
	defer cmap.Unlock()
	cmap.cmap[token] = c
	return c,token
}

func RemoveChannel(channel *Channel) {
	UserRouterI.RemoveFromRouter(channel.token)
	channel.Close()
	LeaveAllRoom(channel)
	channel.conn.Close()
	cmap := GetChannelMap(channel.token)
	cmap.Lock()
	defer cmap.Unlock()

	delete(cmap.cmap,channel.token)
}


func GetChannelByToken(token string) (*Channel,error){
	var channel *Channel
	cmap := GetChannelMap(token)
	cmap.Lock()
	defer cmap.Unlock()
	channel = cmap.cmap[token]

	if channel == nil {
		return nil, errors.New(fmt.Sprint("not exist channel of key token :", token))
	}
	return channel,nil
}

func GetChannelByUserid(userid string) ([]*Channel,error){
	var channels []*Channel = []*Channel{}
	if tokens,err := UserRouterI.GetFromRouter(userid);err != nil{
		return nil,err
	}else {
		for node := tokens.root;node != nil;node = node.next  {
			token := node.value.(string)
			cmap := GetChannelMap(token)
			cmap.Lock()
			channel := cmap.cmap[token]
			channels = append(channels,channel)
			cmap.Unlock()
		}
	}
	if len(channels) == 0{
		return nil, errors.New(fmt.Sprint("not exist channel of userid :", userid))
	}
	return channels,nil
}

func GetChannelMap(token string) *ChannelMap{
	index := ring.Hash(token)
	return ChannelMapInstance[index]
}

func GetOnlineUser() []string{
	var users []string = []string{}
	for _,cmap := range ChannelMapInstance{
		for token,_ := range cmap.cmap{
			users = append(users,token)
		}
	}
	return users
}


func montorChannelMap(){
	for{
		var count int = 0
		for _,cmap := range ChannelMapInstance {
			count += len(cmap.cmap)
		}
		fmt.Println("====================Connect State",count,"========================")
		for _,cmap := range ChannelMapInstance{
			for key,_ := range cmap.cmap{
				fmt.Println(fmt.Sprintf("\"%s\",",key))
			}
		}
		fmt.Println("==========================",count,"====================================")

		time.Sleep(10*time.Second)
	}
}



